
#include <arpa/inet.h>
#include <cstring>
#include <iostream>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <vector>
#include <cerrno>

class EpollServer
{
public:
    ~EpollServer()
    {
        if (_epfd >= 0)
            close(_epfd);
        if (_listen_fd >= 0)
            close(_listen_fd);
    }

    // 启动服务器
    void Run()
    {
        if (!Init())
            return;
        std::cout << "Listening on 0.0.0.0:8080, press q+Enter to quit\n";
        Loop();
    }

private:
    int _epfd = -1;
    int _listen_fd = -1;
    std::vector<epoll_event> _events{16}; // 默认 16 槽位

    // ---------- 初始化 ----------
    bool Init()
    {
        // 1. 创建监听套接字
        _listen_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_fd < 0)
        {
            perror("socket");
            return false;
        }

        // 2. 设置 SO_REUSEADDR（可选）
        int opt = 1;
        setsockopt(_listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

        // 3. 绑定地址
        sockaddr_in addr{};
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(8080);
        if (bind(_listen_fd, (sockaddr *)&addr, sizeof(addr)) < 0)
        {
            perror("bind");
            return false;
        }

        // 4. 开始监听
        if (listen(_listen_fd, 5) < 0)
        {
            perror("listen");
            return false;
        }

        //非阻塞不是 epoll 独有，而是 “单线程事件循环模型”的通用约定
        //非阻塞，在 epoll 的 ET（边缘触发）模式下几乎必须这么做，，否则会出现“饿死”或阻塞风险。
        // 5. 设为非阻塞，
        fcntl(_listen_fd, F_SETFL, O_NONBLOCK);

        // 6. 创建 epoll 实例
        _epfd = epoll_create1(0);
        if (_epfd < 0)
        {
            perror("epoll_create1");
            return false;
        }

        // 7. 把监听 fd 加入 epoll
        epoll_event ev{};
        ev.events = EPOLLIN;
        ev.data.fd = _listen_fd;
        if (epoll_ctl(_epfd, EPOLL_CTL_ADD, _listen_fd, &ev) < 0)
        {
            perror("epoll_ctl(listen_fd)");
            return false;
        }

        // 8. 把标准输入加入 epoll
        ev.events = EPOLLIN;
        ev.data.fd = STDIN_FILENO;
        if (epoll_ctl(_epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) < 0)
        {
            perror("epoll_ctl(stdin)");
            return false;
        }
        return true;
    }

    // ---------- 事件循环 ----------
    void Loop()
    {
        while (true)
        {
            //epoll_wait，将fd拿出来进行IO处理
            int n = epoll_wait(_epfd, _events.data(),
                               static_cast<int>(_events.size()), -1);
            if (n < 0)
            {
                if (errno == EINTR)
                    continue; // 被信号中断，重来
                perror("epoll_wait");
                break;
            }
            Dispatcher(n);
        }
    }

    // ---------- 分发器 ----------
    void Dispatcher(int fd_num)
    {
        for (int i = 0; i < fd_num; ++i)
        {
            int fd = _events[i].data.fd;
            uint32_t ev = _events[i].events;

            if (ev & EPOLLIN)
            {
                if (fd == _listen_fd)
                {
                    Accepter(); // 连接处理器
                }
                else if (fd == STDIN_FILENO)
                {
                    HandleStdin(); // 标准输入处理器
                }
                else
                {
                    Recver(fd); // 数据处理器
                }
            }
            // 可扩展 EPOLLOUT / EPOLLERR / EPOLLHUP ...
        }
    }

    // ---------- 连接处理器 ----------
    void Accepter()
    {
        sockaddr_in client_addr{};
        socklen_t len = sizeof(client_addr);
        int conn_fd = accept4(_listen_fd, (sockaddr *)&client_addr,
                              &len, SOCK_NONBLOCK);
        if (conn_fd >= 0)
        {
            std::cout << "New connection from "
                      << inet_ntoa(client_addr.sin_addr) << ":"
                      << ntohs(client_addr.sin_port) << "\n";
            // 示例：直接关闭，可改为加入 epoll 继续收发
            close(conn_fd);
        }
        else if (errno != EAGAIN && errno != EWOULDBLOCK)
        {
            perror("accept4");
        }
    }

    // ---------- 数据处理器 ----------
    void Recver(int client_fd)
    {
        char buf[1024];
        ssize_t n = recv(client_fd, buf, sizeof(buf), 0);
        if (n > 0)
        {
            // 这里可以解析协议并回写数据
            // 示例：直接丢弃
            (void)buf;
        }
        else if (n == 0 || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK))
        {
            // 对端关闭或出错
            close(client_fd);
        }
    }

    // ---------- 标准输入处理器 ----------
    void HandleStdin()
    {
        char buf[128];
        if (fgets(buf, sizeof(buf), stdin))
        {
            if (buf[0] == 'q')
            {
                std::cout << "Quit by user\n";
                exit(0);
            }
        }
    }
};

// ---------- main ----------
int main()
{
    EpollServer server;
    server.Run();
    return 0;
}